#include "GLWidget.h"

GLWidget::GLWidget(QWidget *parent): QOpenGLWidget(parent) {
    setMouseTracking(true);
}

void GLWidget::initializeGL() {
    initializeOpenGLFunctions();
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    qDebug() << "OpenGL initialized";

    // 创建着色器程序
    m_program = new QOpenGLShaderProgram(this);
    if (!m_program->addShaderFromSourceCode(QOpenGLShader::Vertex,
                                            "#version 330 core\n"
                                            "layout(location = 0) in vec2 position;\n"
                                            "uniform mat4 projection;\n"
                                            "void main() {\n"
                                            "    gl_Position = projection * vec4(position, 0.0, 1.0);\n"
                                            "}")) {
        qDebug() << "Vertex shader error:" << m_program->log();
    }
    if (!m_program->addShaderFromSourceCode(QOpenGLShader::Fragment,
                                            "#version 330 core\n"
                                            "uniform vec4 color;\n"
                                            "out vec4 fragColor;\n"
                                            "void main() {\n"
                                            "    fragColor = color;\n"
                                            "}")) {
        qDebug() << "Fragment shader error:" << m_program->log();
    }
    if (!m_program->link()) {
        qDebug() << "Shader link error:" << m_program->log();
    }

    // 创建VBO
    m_vbo.create();
    qDebug() << "VBO created";
}

void GLWidget::resizeGL(int w, int h) {
    glViewport(0, 0, w, h);
    m_width = w;
    m_height = h;
    updateProjection();
    qDebug() << "Resized to" << w << "x" << h;
}

void GLWidget::paintGL() {
    glClear(GL_COLOR_BUFFER_BIT);

    if (!m_program->bind()) {
        qDebug() << "Failed to bind shader program";
        return;
    }

    // 设置投影矩阵
    m_program->setUniformValue("projection", m_projection);

    // 绘制上下标尺
    drawRulers();

    // 绘制鼠标位置相关线条和区域
    if (!m_mousePos .isNull()) {
        drawMouseIndicators();
    }

    m_program->release();
}

void GLWidget::mouseMoveEvent(QMouseEvent *event) {
    QPointF pos = event->position();
    if (event->buttons() & Qt::LeftButton) {
        float deltaX = (pos.x() - m_lastMousePos.x()) / m_scale;
        m_offsetX -= deltaX;
        updateProjection();
    }
    m_mousePos = pos;
    m_lastMousePos = pos;
    update();
}

void GLWidget::mousePressEvent(QMouseEvent *event) {
    if (event->button() == Qt::LeftButton) {
        m_lastMousePos = event->position();
    }
}

void GLWidget::wheelEvent(QWheelEvent *event) {
    QPoint numDegrees = event->angleDelta() / 8;
    if (!numDegrees.isNull()) {
        float zoomFactor = numDegrees.y() > 0 ? 1.1f : 0.9f;
        float oldScale = m_scale;

        // 更新缩放比例（限制在合理范围内）
        m_scale = qBound(10.0f, m_scale * zoomFactor, 500.0f);

        // 计算鼠标在世界坐标中的位置
        QPointF mousePos = event->position();
        float worldX = (mousePos.x() - m_width/2.0f) / oldScale + m_offsetX;

        // 调整偏移量以保持鼠标位置的世界坐标不变
        m_offsetX = worldX - (mousePos.x() - m_width/2.0f) / m_scale;

        updateProjection();
        update();
    }
}

void GLWidget::updateProjection() {
    m_projection.setToIdentity();
    m_projection.ortho(-m_width/2.0f, m_width/2.0f,
                       -m_height/2.0f, m_height/2.0f,
                       -1.0f, 1.0f);
}

void GLWidget::drawRulers() {
    // 计算可见范围
    float leftWorld = m_offsetX - m_width/(2.0f * m_scale);
    float rightWorld = m_offsetX + m_width/(2.0f * m_scale);

    // 确定起始和结束刻度
    int startCm = static_cast<int>(std::floor(leftWorld));
    int endCm = static_cast<int>(std::ceil(rightWorld));

    // 标尺高度
    const float rulerHeight = 30.0f;

    // 绘制上下标尺背景
    drawRect(-m_width/2.0f, m_height/2.0f - rulerHeight,
             m_width, rulerHeight, QVector4D(0.7f, 0.7f, 0.7f, 1.0f));
    drawRect(-m_width/2.0f, -m_height/2.0f,
             m_width, rulerHeight, QVector4D(0.7f, 0.7f, 0.7f, 1.0f));

    // 绘制刻度线
    for (int cm = startCm; cm <= endCm; cm++) {
        float xPos = (cm - m_offsetX) * m_scale;
        float tickHeight = (cm % 5 == 0) ? 20.0f : 10.0f;

        // 上标尺刻度
        drawLine(xPos, m_height/2.0f,
                 xPos, m_height/2.0f - tickHeight,
                 QVector4D(1.0f, 1.0f, 1.0f, 1.0f));

        // 下标尺刻度
        drawLine(xPos, -m_height/2.0f,
                 xPos, -m_height/2.0f + tickHeight,
                 QVector4D(1.0f, 1.0f, 1.0f, 1.0f));
    }
}

void GLWidget::drawMouseIndicators() {
    if (m_mousePos.isNull()) return;

    // 计算鼠标位置的世界坐标
    float mouseWorldX = (m_mousePos.x() - m_width/2.0f) / m_scale + m_offsetX;

    // 计算三条垂直线位置
    float centerX = (mouseWorldX - m_offsetX) * m_scale;
    float leftX = ((mouseWorldX - 0.5f) - m_offsetX) * m_scale;
    float rightX = ((mouseWorldX + 0.5f) - m_offsetX) * m_scale;

    // 绘制半透明填充区域
    drawRect(leftX, -m_height/2.0f,
             rightX - leftX, m_height,
             QVector4D(0.0f, 1.0f, 0.0f, 0.01f));

    // 绘制三条垂直线
    drawLine(leftX, -m_height/2.0f, leftX, m_height/2.0f,
             QVector4D(1.0f, 1.0f, 0.0f, 1.0f));
    drawLine(centerX, -m_height/2.0f, centerX, m_height/2.0f,
             QVector4D(1.0f, 1.0f, 0.0f, 1.0f));
    drawLine(rightX, -m_height/2.0f, rightX, m_height/2.0f,
             QVector4D(1.0f, 1.0f, 0.0f, 1.0f));
}

void GLWidget::drawLine(float x1, float y1, float x2, float y2, const QVector4D &color) {
    QVector<QVector2D> verts = {
        QVector2D(x1, y1),
        QVector2D(x2, y2)
    };

    m_vbo.bind();
    m_vbo.allocate(verts.constData(), verts.size() * sizeof(QVector2D));

    m_program->enableAttributeArray(0);
    m_program->setAttributeBuffer(0, GL_FLOAT, 0, 2, 0);
    m_program->setUniformValue("color", color);

    glDrawArrays(GL_LINES, 0, verts.size());

    m_vbo.release();
}

void GLWidget::drawRect(float x, float y, float width, float height, const QVector4D &color) {
    QVector<QVector2D> verts = {
        QVector2D(x, y),
        QVector2D(x + width, y),
        QVector2D(x + width, y + height),
        QVector2D(x, y + height)
    };

    m_vbo.bind();
    m_vbo.allocate(verts.constData(), verts.size() * sizeof(QVector2D));

    m_program->enableAttributeArray(0);
    m_program->setAttributeBuffer(0, GL_FLOAT, 0, 2, 0);
    m_program->setUniformValue("color", color);

    glDrawArrays(GL_TRIANGLE_FAN, 0, verts.size());

    m_vbo.release();
}
